package cn.miju.unionpay.handler;

import cn.hutool.core.collection.CollUtil;
import cn.miju.unionpay.constant.UnionPayConstant;
import cn.miju.unionpay.model.UnionPayRequest;
import cn.miju.unionpay.model.UnionPayResponse;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * <pre>
 * 支付能力抽象类
 * </pre>
 *
 * @author zhuming
 * @version 1.0.0
 * @since 2023-02-28 11:29
 */
@Slf4j
public abstract class AbstractUnionPayHandler<REQ, RESP> {

    /**
     * 请求参数前置处理
     * @param req 请求参数
     * @return 结果
     */
    public UnionPayRequest beforeRequest(REQ req) {
        UnionPayRequest request = new UnionPayRequest();
        // 银联全渠道系统，产品参数，无需修改
        request.setVersion(UnionPayConstant.VERSION);
        request.setEncoding(UnionPayConstant.ENCODING);
        request.setSignMethod(UnionPayConstant.SIGN_METHOD);
        request.setAccessType(UnionPayConstant.ACCESS_TYPE);
        request.setTxnTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
        return request;
    }

    /**
     * 核心执行
     * @param req 请求参数
     * @return 结果
     */
    public abstract RESP doPlan(REQ req);

    /**
     * 响应参数后置处理
     * @param response 响应参数
     * @return 结果
     */
    public abstract RESP afterResponse(UnionPayResponse response);

    /**
     * 添加自定义可选参数到请求参数类
     * @param reqData 请求参数类
     * @param optionalReqParams 自定义可选请求参数
     */
    public void setOptionalReqParams(Object reqData, Map<String, Object> optionalReqParams) {
        if (CollUtil.isNotEmpty(optionalReqParams)) {
            optionalReqParams.forEach((key, value) -> {
                if (Objects.nonNull(value) && value instanceof String) {
                    try {
                        Field field = reqData.getClass().getDeclaredField(key);
                        field.setAccessible(true);
                        field.set(reqData, String.valueOf(value));
                        field.setAccessible(false);
                    } catch (Exception e) {
                        try {
                            Field superField = reqData.getClass().getSuperclass().getDeclaredField(key);
                            superField.setAccessible(true);
                            superField.set(reqData, String.valueOf(value));
                            superField.setAccessible(false);
                        } catch (Exception ex) {
                            log.error("添加自定义请求参数失败！", e);
                        }
                    }
                }
            });
        }
    }
    /**
     * 获取自定义可选返回参数
     * @param respData 返回参数类
     * @param optionalRespParams 自定义可选返回参数
     */
    public Map<String, Object> getOptionalRespParams(Object respData, Set<String> optionalRespParams) {
        if (CollUtil.isNotEmpty(optionalRespParams)) {
            Map<String, Object> responseParams = Maps.newHashMap();
            optionalRespParams.forEach(key -> {
                try {
                    Field field = respData.getClass().getDeclaredField(key);
                    field.setAccessible(true);
                    String name = field.getName();
                    Object value = field.get(respData);
                    field.setAccessible(false);
                    responseParams.put(name, String.valueOf(value));
                } catch (Exception e) {
                    try {
                        Field superField = respData.getClass().getSuperclass().getDeclaredField(key);
                        superField.setAccessible(true);
                        String name = superField.getName();
                        Object value = superField.get(respData);
                        superField.setAccessible(false);
                        responseParams.put(name, String.valueOf(value));
                    } catch (Exception ex) {
                        log.error("添加自定义请求参数失败！", e);
                    }
                }
            });
            return responseParams;
        }
        return Collections.emptyMap();
    }

}
